package com.heihei.imgpreview;

import com.heihei.config.ConfigProperties;
import com.heihei.imgpreview.dto.ImgInfoDTO;
import com.heihei.imgpreview.dto.LineDTO;
import com.heihei.util.*;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;

/**
 *  创建预览，直接本地创建图片
 *
 * @version 1.0
 * @since JDK1.8
 * @author duanhengfei
 * @date 2021年01月29日 16:49:48
 */
public class GeneratePreviewImg {

    public static void main(String[] args) throws IOException {
        start();
    }

    /**
     * 方法描述: 开始交互式 img图片预览生成
     *
     * @param
     * @Return
     * @throws
     * @author duanhengfei
     * @date 2021年01月29日 16:50:49
     */
    private static void start() throws IOException {
        //读取所有图片
        System.out.println(">>开始生成预览图片");
        File validSrcDir = FileUtilF.getValidSrcDir();
        createImgPreview(validSrcDir);
    }

    /**
     * 核心方法： 创建图片预览，在传入的文件夹下，随机抽取指定张图片，生成预览图（抽取的图片张数，见配置文件imgPreview.sampleImgCount）
     * 最终的预览图片生成位置，与传入的文件夹同级
     *
     * @param validSrcDir 需传入一个文件夹 File类型
     * @Return
     * @throws
     * @author duanhengfei
     * @date 2021年01月31日 09:47:36
     */
    public static void createImgPreview(File validSrcDir) throws IOException {
        //读取所有的图片文件 的相对路径
        List<String> allImgStrList = FileUtilF.readAllImgRelativePath(validSrcDir);
        //去除所有的gif图片
        for (int i = allImgStrList.size() - 1; i >= 0; i--) {
            if(allImgStrList.get(i).toLowerCase().endsWith(".gif")) {
                allImgStrList.remove(i);
            }
        }
        if(allImgStrList == null || allImgStrList.size() < 1) {
            return;
        }
        //随机抽 SAMPLE_IMG_COUNT 张（如果总数都不够 SAMPLE_IMG_COUNT 张，那就抽所有符合条件的图片）
        List<ImgInfoDTO> imgDtoList = selectRandomValidImg(validSrcDir, allImgStrList, ConfigProperties.SAMPLE_IMG_COUNT);
        //获取最终的按行数据结构
        List<LineDTO> resultLineDataList = getResultLineDto(imgDtoList);
        //写图片
        writeImg(resultLineDataList, getTargetImgFile(validSrcDir.getParentFile(), validSrcDir.getName()));
    }

    /**
     * 方法描述: 写图片
     *
     * @param resultLineDataList
     * @param targetImgFile
     * @Return
     * @throws
     * @author duanhengfei
     * @date 2021年01月30日 18:08:22
     */
    public static void writeImg(List<LineDTO> resultLineDataList, File targetImgFile) throws IOException {
        int[] backWidthAndHeight = calculateBackGroundWidthAndHeight(resultLineDataList);
        //创建画布
        BufferedImage tag = new BufferedImage(backWidthAndHeight[0],backWidthAndHeight[1],BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = tag.createGraphics();
        //设置颜色为218，223，224
        graphics.setColor(new Color(ConfigProperties.RED, ConfigProperties.GREEN, ConfigProperties.BLUE));
        //填充颜色
        graphics.fillRect(0, 0, backWidthAndHeight[0], backWidthAndHeight[1]);
        //写图片 到 graphics
        writeImg2Graphics(resultLineDataList, graphics);
        graphics.dispose();
//        File targetImgFile = getTargetImgFile(validSrcDir.getParentFile(), validSrcDir.getName());
        ImageIO.write(tag, ConfigProperties.GENERATE_IMG_STYLE, targetImgFile);
    }

    /**
     * 获取目标图片
     *
     * @param
     * @Return {@link File}
     * @throws
     * @author duanhengfei
     * @date 2021年02月01日 13:37:42
     */
    private static File getTargetImgFile(File parentFile, String fileName) {
        File targetImgFile = new File(parentFile, fileName + "_" + ConfigProperties.GENERATE_IMG_SUFFIX + "." + ConfigProperties.GENERATE_IMG_STYLE);
        int index = 1;
        while (targetImgFile.exists()) {
            targetImgFile = new File(parentFile, fileName + "_" + ConfigProperties.GENERATE_IMG_SUFFIX + index + "." + ConfigProperties.GENERATE_IMG_STYLE);
            index++;
        }
        return targetImgFile;
    }

    /**
     * 写图片 到 graphics
     *
     * @param resultLineDataList
     * @param graphics
     * @Return
     * @throws
     * @author duanhengfei
     * @date 2021年01月30日 21:14:30
     */
    private static void writeImg2Graphics(List<LineDTO> resultLineDataList, Graphics2D graphics) {
        int x = ConfigProperties.IMG_INTERVAL;
        int y = ConfigProperties.IMG_INTERVAL;
        for (LineDTO lineDTO : resultLineDataList) {
            Integer lineHeight = lineDTO.getLineHeight();
            List<ImgInfoDTO> imgInfoList = lineDTO.getImgInfoList();
            for (ImgInfoDTO img : imgInfoList) {
//                graphics.drawImage(img.getBufferedImage(), x, y + (lineHeight - img.getHeight()), img.getWidth(), img.getHeight(), null);
                graphics.drawImage(img.getBufferedImage().getScaledInstance(img.getWidth(), img.getHeight(), Image.SCALE_SMOOTH), x, y + (lineHeight - img.getHeight()), img.getWidth(), img.getHeight(), null);
                if(img.getAccrossOrVerticalFlag() == 1) {
                    x += (img.getWidth() + ConfigProperties.ACCROSS_IMG_HORIZONTAL_INTERVAL);
                } else {
                    x += (img.getWidth() + ConfigProperties.IMG_INTERVAL);
                }
            }
            x = ConfigProperties.IMG_INTERVAL;
            y += (lineHeight + ConfigProperties.IMG_INTERVAL);
        }
    }

    /**
     * 方法描述: 计算画布的总宽高
     *
     * @param resultLineDataList
     * @Return {@link int[]} 返回的数组，0索引处是总宽； 1索引处是总高
     * @throws
     * @author duanhengfei
     * @date 2021年01月30日 18:19:09
     */
    private static int[] calculateBackGroundWidthAndHeight(List<LineDTO> resultLineDataList) {
        //计算画布需要的总宽
        //横向图片总宽
        int accrossWidth = (ConfigProperties.ACCROSS_IMG_WIDTH * ConfigProperties.ACCROSS_IMG_LINE_MAX_COUNT) + ((ConfigProperties.ACCROSS_IMG_LINE_MAX_COUNT + 1) * ConfigProperties.IMG_INTERVAL);
        int verticalWidth = (ConfigProperties.VERTICAL_IMG_WIDTH * ConfigProperties.VERTICAL_IMG_LINE_MAX_COUNT) + ((ConfigProperties.VERTICAL_IMG_LINE_MAX_COUNT + 1) * ConfigProperties.IMG_INTERVAL);
        int backGroundWidth = accrossWidth > verticalWidth ? accrossWidth : verticalWidth;
        //计算画布需要的总高
        int backGroundHeight = 0;
        for (LineDTO lineDTO : resultLineDataList) {
            backGroundHeight += lineDTO.getLineHeight();
        }
        backGroundHeight += (resultLineDataList.size() + 1) * ConfigProperties.IMG_INTERVAL;
        int[] backWidthAndHeightArr = new int[2];
        backWidthAndHeightArr[0] = backGroundWidth;
        backWidthAndHeightArr[1] = backGroundHeight;
        return backWidthAndHeightArr;
    }

    /**
     * 方法描述: img分组，分行
     *
     * @param imgDtoList
     * @Return {@link List< LineDTO>}
     * @throws
     * @author duanhengfei
     * @date 2021年01月29日 18:09:29
     */
    public static List<LineDTO> getResultLineDto(List<ImgInfoDTO> imgDtoList) {
        //分组
        List<List<ImgInfoDTO>> groupList = divideGroup(imgDtoList);
        //按行构建数据
        List<LineDTO> resultLineDTOList = buildDataLineResult(groupList.get(0), groupList.get(1));
        return resultLineDTOList;
    }

    /**
     * 方法描述: 往resultLineDTOList里面增加一行
     *
     * @param accrossImgList
     * @param verticalImgList
     * @Return
     * @throws
     * @author duanhengfei
     * @date 2021年01月30日 09:13:40
     */
    private static List<LineDTO> buildDataLineResult(List<ImgInfoDTO> accrossImgList, List<ImgInfoDTO> verticalImgList) {
        //第一行随机取横或者纵 （1横  2纵）
        int flag = NumberUtilF.getRandom().nextInt(2) + 1;
        List<LineDTO> resultLineDTOList = new ArrayList<>();
        while (accrossImgList.size() >= ConfigProperties.ACCROSS_IMG_LINE_MAX_COUNT && verticalImgList.size() >= ConfigProperties.VERTICAL_IMG_LINE_MAX_COUNT) {
            if(flag == 1) {
                //横
                if(accrossImgList.size() >= ConfigProperties.ACCROSS_IMG_LINE_MAX_COUNT) {
                    //正常增加横，并且最后把flag变为2
                    addOneLineAccross(resultLineDTOList, accrossImgList, verticalImgList, flag);
                }
                flag = 2;
            }
            if(flag == 2) {
                //纵
                if(verticalImgList.size() >= ConfigProperties.VERTICAL_IMG_LINE_MAX_COUNT) {
                    //正常增加纵，并且最后把flag变为1
                    addOneLineAccross(resultLineDTOList, accrossImgList, verticalImgList, flag);
                }
                flag = 1;
            }
        }
        while(accrossImgList.size() >= ConfigProperties.ACCROSS_IMG_LINE_MAX_COUNT) {
            addOneLineAccross(resultLineDTOList, accrossImgList, verticalImgList, 1);
        }
        while(verticalImgList.size() >= ConfigProperties.VERTICAL_IMG_LINE_MAX_COUNT) {
            addOneLineAccross(resultLineDTOList, accrossImgList, verticalImgList, 2);
        }
        //计算总宽度（不包括边框、间隔）
        int accrossWidth = ConfigProperties.ACCROSS_IMG_WIDTH * ConfigProperties.ACCROSS_IMG_LINE_MAX_COUNT;
        int verticalWidth = ConfigProperties.VERTICAL_IMG_WIDTH * ConfigProperties.VERTICAL_IMG_LINE_MAX_COUNT;
        int totalWidth = accrossWidth > verticalWidth ? accrossWidth : verticalWidth;
        //到现在为止，accrossImgList和verticalImgList各自都已经不足一行之数了，拼装最后两行图片
        List<ImgInfoDTO> remindImgList = new ArrayList<>();
        if((NumberUtilF.getRandom().nextInt(2) + 1) == 1) {
            remindImgList.addAll(accrossImgList);
            remindImgList.addAll(verticalImgList);
        } else {
            remindImgList.addAll(verticalImgList);
            remindImgList.addAll(accrossImgList);
        }
        //开始添加最后两行
        LineDTO currLine = LineDTO.initializeLineDTO();
        int currWidth = 0;
        for (ImgInfoDTO img : remindImgList) {
            if(currWidth + img.getWidth() > totalWidth) {
                resultLineDTOList.add(currLine);
                currLine = LineDTO.initializeLineDTO();
                currWidth = 0;
            }
            currLine.getImgInfoList().add(img);
            if(img.getHeight() > currLine.getLineHeight()) {
                currLine.setLineHeight(img.getHeight());
            }
            currWidth += img.getWidth();
        }
        //追加最后一行
        if(currLine.getImgInfoList().size() > 0) {
            resultLineDTOList.add(currLine);
        }
        return resultLineDTOList;
    }

    /**
     * 方法描述: 往resultLineDTOList内，添加一行横向图片
     *
     * @param resultLineDTOList
     * @param accrossImgList
     * @Return
     * @throws
     * @author duanhengfei
     * @date 2021年01月30日 09:28:24
     */
    private static void addOneLineAccross(List<LineDTO> resultLineDTOList, List<ImgInfoDTO> accrossImgList, List<ImgInfoDTO> verticalImgList, int flag) {
        List<ImgInfoDTO> dataList = new ArrayList<>();
        int lineMaxCount = 0;
        if(flag == 1) {
            //横
            dataList = accrossImgList;
            lineMaxCount = ConfigProperties.ACCROSS_IMG_LINE_MAX_COUNT;
        } else {
            //纵
            dataList = verticalImgList;
            lineMaxCount = ConfigProperties.VERTICAL_IMG_LINE_MAX_COUNT;
        }
        //如果数据为0，则不再增加
        if(dataList.size() == 0) {
            return;
        }

        LineDTO line = new LineDTO();
        line.setLineHeight(dataList.get(0).getHeight());
        line.setImgInfoList(new ArrayList<>());
        for (int i = 0; i < lineMaxCount && dataList.size() > 0; i++) {
            ImgInfoDTO imgInfoDTO = dataList.get(0);
            line.getImgInfoList().add(imgInfoDTO);
            if(imgInfoDTO.getHeight() > line.getLineHeight()) {
                line.setLineHeight(imgInfoDTO.getHeight());
            }
            dataList.remove(0);
        }
        resultLineDTOList.add(line);
    }

    /**
     * 分组，并且格式化宽高
     *
     * @param imgDtoList
     * @Return {@link List< List< ImgInfoDTO>>} 返回结果，0索引位置是横向图片List，1索引位置是纵向图片List
     * @throws
     * @author duanhengfei
     * @date 2021年01月29日 19:32:03
     */
    private static List<List<ImgInfoDTO>> divideGroup(List<ImgInfoDTO> imgDtoList) {
        List<ImgInfoDTO> accrossImgDtoList = new ArrayList<>();
        List<ImgInfoDTO> verticalImgDtoList = new ArrayList<>();
        for (ImgInfoDTO imgInfoDTO : imgDtoList) {
            //改动：这里不再格式化宽高，直接在加载图片的同时，格式化宽高
            if(imgInfoDTO.getAccrossOrVerticalFlag() == 1) {
                accrossImgDtoList.add(imgInfoDTO);
            } else {
                verticalImgDtoList.add(imgInfoDTO);
            }
        }
        return Arrays.asList(accrossImgDtoList, verticalImgDtoList);
    }

    /**
     * 方法描述: 从已有图片List中，抽取20张符合条件的图片
     *
     *
     * @param parentDir
     * @param allImgList
     * @param count
     * @Return {@link List< String>}
     * @throws
     * @author duanhengfei
     * @date 2021年01月29日 17:36:04
     */
    private static List<ImgInfoDTO> selectRandomValidImg(File parentDir, List<String> allImgList, int count) {
        List<ImgInfoDTO> resultImgList = new ArrayList<>();
        addImg(parentDir, allImgList, resultImgList, count);
        while(allImgList.size() > 0 && resultImgList.size() < count) {
            addImg(parentDir, allImgList, resultImgList, count);
        }
        return resultImgList;
    }

    /**
     * 方法描述: 添加图片（并格式化宽高）
     *
     * @param parentDir
     * @param allImgList
     * @param resultImgList
     * @param count
     * @Return
     * @throws
     * @author duanhengfei
     * @date 2021年01月29日 17:58:40
     */
    private static void addImg(File parentDir, List<String> allImgList, List<ImgInfoDTO> resultImgList, int count) {
        List<String> imgList = CollectionUtilF.selectRandomElementFromList(allImgList, count - resultImgList.size());
        for (String imgRelativePathStr : imgList) {
            File imgFile = new File(parentDir, imgRelativePathStr);
            BufferedImage img = ImgUtil.loadImageLocal(imgFile);
            if(img == null) {
                System.out.println("null " + imgFile.getAbsoluteFile());
                continue;
            }
            int width = img.getWidth();
            int height = img.getHeight();
            double widthDivideHeight = width * 1D / height;
            if(widthDivideHeight >= ConfigProperties.MIN_WIDTH_DIVIDE_HEIGHT && widthDivideHeight <= ConfigProperties.MAX_WIDTH_DIVIDE_HEIGHT) {
                ImgInfoDTO dto = new ImgInfoDTO();
                dto.setFile(imgFile);
                dto.setBufferedImage(img);
                dto.setRelativePath(imgRelativePathStr);
                //用accrossOrVerticalFlag字段区分 横款和纵款 图片
                //并格式化宽高
                if(widthDivideHeight > 1.2) {
                    dto.setAccrossOrVerticalFlag(1);
                    dto.setWidth(ConfigProperties.ACCROSS_IMG_WIDTH);
                    dto.setHeight(new Double(ConfigProperties.ACCROSS_IMG_WIDTH / widthDivideHeight).intValue());
                } else {
                    dto.setAccrossOrVerticalFlag(2);
                    dto.setWidth(ConfigProperties.VERTICAL_IMG_WIDTH);
                    dto.setHeight(new Double(ConfigProperties.VERTICAL_IMG_WIDTH / widthDivideHeight).intValue());
                }
                resultImgList.add(dto);
            }
        }
        allImgList.removeAll(imgList);
    }

    /**
     * 方法描述: 添加图片，并格式化宽高
     *
     * @param imgList
     * @Return {@link List< ImgInfoDTO>}
     * @throws
     * @author duanhengfei
     * @date 2021年02月12日 22:48:52
     */
    public static List<ImgInfoDTO> addImg(List<File> imgList, int flag) {
        List<BufferedImage> bufferedImgList = new ArrayList<>();
        for (File imgFile : imgList) {
            BufferedImage img = ImgUtil.loadImageLocal(imgFile);
            bufferedImgList.add(img);
        }
        return addImg(bufferedImgList);
    }

    /**
     * 方法描述: 添加图片，并格式化宽高
     *
     * @param bufferImgList
     * @Return {@link List< ImgInfoDTO>}
     * @throws
     * @author duanhengfei
     * @date 2021年02月12日 22:48:52
     */
    public static List<ImgInfoDTO> addImg(List<BufferedImage> bufferImgList) {
        List<ImgInfoDTO> resultImgList = new ArrayList<>();
        for (BufferedImage img : bufferImgList) {
            if(img == null) {
                continue;
            }
            ImgInfoDTO info = transImg2ImgInfoDTO(img);
            if(info != null) {
                resultImgList.add(info);
            }
        }
        return resultImgList;
    }

    public static ImgInfoDTO transImg2ImgInfoDTO(BufferedImage img) {
        int width = img.getWidth();
        int height = img.getHeight();
        double widthDivideHeight = width * 1D / height;
        if(widthDivideHeight >= ConfigProperties.MIN_WIDTH_DIVIDE_HEIGHT && widthDivideHeight <= ConfigProperties.MAX_WIDTH_DIVIDE_HEIGHT) {
            ImgInfoDTO dto = new ImgInfoDTO();
            dto.setBufferedImage(img);
            //用accrossOrVerticalFlag字段区分 横款和纵款 图片
            //并格式化宽高
            if(widthDivideHeight > 1.2) {
                dto.setAccrossOrVerticalFlag(1);
                dto.setWidth(ConfigProperties.ACCROSS_IMG_WIDTH);
                dto.setHeight(new Double(ConfigProperties.ACCROSS_IMG_WIDTH / widthDivideHeight).intValue());
            } else {
                dto.setAccrossOrVerticalFlag(2);
                dto.setWidth(ConfigProperties.VERTICAL_IMG_WIDTH);
                dto.setHeight(new Double(ConfigProperties.VERTICAL_IMG_WIDTH / widthDivideHeight).intValue());
            }
            return dto;
        } else {
            return null;
        }
    }

}